using System;
using GalaSoft.MvvmLight;
using System.Collections.ObjectModel;
using Locator.Silverlight.Client.Models.ViewModels.Elements;
using Locator.Silverlight.Client.Models.PersonalLocationsServiceReference;
using GalaSoft.MvvmLight.Command;
using System.Windows;
using System.Collections.Generic;

namespace Locator.Silverlight.Client.Models.ViewModels.Screens
{
    public class ManagePersonalLocationsViewModel : ViewModelBase
    {
        public ObservableCollection<PersonalLocationViewModel> UserLocations { get; set; }

        private readonly IPersonalLocationModel personalLocationModel;

        public ManagePersonalLocationsViewModel()
            : this(new PersonalLocationModel())
        {

        }

        public ManagePersonalLocationsViewModel(IPersonalLocationModel service)
        {
            this.personalLocationModel = service;

#if DEBUG
            if (IsInDesignMode)
            {
                this.UserLocations = new ObservableCollection<PersonalLocationViewModel>() 
                {
                    new PersonalLocationViewModel(new PersonalLocation()
                    { 
                        Description = "Home",
                        Latitude = 43.474249M, 
                        Longitude = -79.732728M 
                    })
                };
            }
#endif

            if (!IsInDesignMode)
            {
                this.UserLocations = new ObservableCollection<PersonalLocationViewModel>();
                this.Refresh();
            }

            this.Provinces = new List<string>() { "Ontario", "Manitoba", "Quebec" };
            this.Province = this.Provinces[0];
            this.LocateAddressCommand = new RelayCommand(() => this.LocateAddress());
            this.LocatePostalCodeCommand = new RelayCommand(() => this.LocatePostalCode());
            this.AddLocationCommand = new RelayCommand(() => this.AddLocation());
            this.RemoveLocationCommand = new RelayCommand<PersonalLocationViewModel>((personalLocation) => this.RemoveLocation(personalLocation));
        }

        private void RemoveLocation(PersonalLocationViewModel personalLocation)
        {
            this.personalLocationModel.DeletePersonalLocationForCurrentUserAsync(personalLocation.Id, (error) =>
            {
                if (error != null)
                {
                    MessageBox.Show(error.Message);
                    return;
                }

                this.Refresh();
            });
        }

        private void AddLocation()
        {
            this.personalLocationModel.AddPersonalLocationForCurrentUserAsync(this.Description, (double)this.Latitude, (double)this.Longitude, (error) => 
            {
                if (error != null)
                {
                    MessageBox.Show(error.Message);
                    return;
                }

                this.Refresh();
            });
        }

        private void LocatePostalCode()
        {
            this.personalLocationModel.SearchByPostalCodeAsync(this.PostalCode, "CANADA", (location, error)=>{
                if (error != null)
                {
                    MessageBox.Show(error.Message);
                    return;
                }

                this.Latitude = (double?)location.Latitude;
                this.Longitude = (double?)location.Longitude;
            });
        }

        private void LocateAddress()
        {
            this.personalLocationModel.SearchByAddressAsync(this.Address, "CANADA", this.Province, this.City, (location, error)=>
            {
                if (error != null)
                {
                    MessageBox.Show(error.Message);
                    return;
                }

                this.Latitude = (double?)location.Latitude;
                this.Longitude = (double?)location.Longitude;
            });
        }

        private void Refresh()
        {
            personalLocationModel.GetPersonalLocationsForCurrentUserAsync((locations, error) =>
            {
                if (error != null)
                {
                    // Display error, normally this would be done through a property
                    MessageBox.Show(error.Message);
                    return;
                }

                this.UserLocations.Clear();
                foreach (var location in locations)
                {
                    this.UserLocations.Add(location);
                }
            });
        }

        public RelayCommand LocateAddressCommand { get; set; }

        public RelayCommand LocatePostalCodeCommand { get; set; }

        public RelayCommand AddLocationCommand { get; set; }

        public string PostalCode { get; set; }

        public string Address { get; set; }

        public string City { get; set; }

        public string Province { get; set; }

        public List<string> Provinces { get; set; }

        /// <summary>
        /// The <see cref="Latitude" /> property's name.
        /// </summary>
        public const string LatitudePropertyName = "Latitude";

        private double? latitude = null;

        /// <summary>
        /// Gets the Latitude property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public double? Latitude
        {
            get { return latitude; }

            set
            {
                if (latitude == value)
                {
                    return;
                }

                latitude = value;

                // Update bindings, no broadcast
                RaisePropertyChanged(LatitudePropertyName);
            }
        }

        /// <summary>
        /// The <see cref="Longitude" /> property's name.
        /// </summary>
        public const string LongitudePropertyName = "Longitude";

        private double? longitude = null;

        /// <summary>
        /// Gets the Latitude property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public double? Longitude
        {
            get { return longitude; }
            set
            {
                if (longitude == value)
                {
                    return;
                }

                longitude = value;

                // Update bindings, no broadcast
                RaisePropertyChanged(LongitudePropertyName);
            }
        }

        public string Description { get; set; }

        public RelayCommand<PersonalLocationViewModel> RemoveLocationCommand { get; set; }
    }
}
